package com.netscenery.yang.model;
/**
 * ����������YANGģ��Ԫ�صĸ��࣬������YANGģ��Ԫ�ع��еĻ���Ϊ
 */
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

import com.netscenery.util.*;
import com.netscenery.yang.YangKeyword;
import com.netscenery.yang.YangStatement;
import com.netscenery.yang.designer.MapInfo;
import com.netscenery.yang.parser.YangParserException;
import com.netscenery.yang.writer.YangFormatter;
import com.netscenery.yang.writer.YangWriter;




public abstract class ModelElement implements ILinkData{
	protected String name;
	protected String prefix;
	protected Env env;
	protected String errorMsg;
	protected ArrayList<YangUnknown> unknowns;
	protected MapInfo mapInfo;
	protected boolean isUpdated;
	/**
	 * ���¶��������
	 */
	public static final int MODELELEMENT_OK = 0;
	public static final int MODELELEMENT_UNSUPPORT = 1;
	public static final int MODELELEMENT_DUPLICATE = 2;
	public static final int MODELELEMENT_NOTFOUND = 3;
	public static final int MODELELEMENT_FAIL = -1;
	/**
	 * 
	 */
	public ModelElement(){
		
	}
	/**
	 * 
	 * @param env
	 * @param name
	 * @throws ModelException 
	 */
	public ModelElement(Env env,String name) throws ModelException{
		if (null == env){
			this.env = new Env();
		}
		else {
			this.env = env;
		}
		Module curModule = env.getCurModule();
		if (null != curModule){
			if (curModule instanceof MainModule){
				prefix = ((MainModule)(curModule)).getPrefix();
			}
			else {
				BelongsTo b = ((SubModule)(curModule)).getBelongsto();
				MainModule mm = (MainModule)env.getModule(b.getName());
				if (null != mm){
					prefix = mm.getPrefix();
				}
				else {
					throw new ModelException(ErrTag.ERROR,"no main module");
				}
				
			}
		}
		if(!setName(name)){
			throw new ModelException(ErrTag.ERROR, "invalid name");
		}
		
	}
	
	/**
	 * 
	 * @param env
	 * @param name
	 */
	public ModelElement(Env env,QName qname){
		if (null == env){
			this.env = new Env();
		}
		else {
			this.env = env;
		}
		if (null == qname){
			return;
		}
		String name = qname.getLocalName();
		String prefix = qname.getPrefix();
		
		if (null == prefix){
			Module curModule = env.getCurModule();
			if (null != curModule){
				if (curModule instanceof MainModule){
					prefix = ((MainModule)(curModule)).getPrefix();
				}
				else {
					BelongsTo b = ((SubModule)(curModule)).getBelongsto();
					MainModule mm = (MainModule)env.getModule(b.getName());
					prefix = mm.getPrefix();
				}
			}
		}
		setPrefix(prefix);
		setName(name);
		
	}
	
	/**
	 * ���������һ��ģ������ȡ��ģ��Ԫ�ص�QName��
	 * ����Ҫ���㱾ģ��Ԫ�����ڵ�ģ���Ƿ�������һ��ģ�鵼���ģ��
	 * ����ǣ����ڻ�ȡ��ģ��Ԫ�����ڵ�ģ��������һ��ģ���ǰ׺��
	 * Ȼ���ټ���QName�����⣬���ģ��Ԫ�ر����prefix�����Լ�
	 * ģ��ģ�����Ҫ��ȡ���������ڵ�ģ�飬Ȼ���ټ����ģ��������һ��
	 * ģ���е�ǰ׺��ʲô
	 * @param curModule
	 * @return
	 */
	public QName  getQName(Module module){
		if(null == module){
			return null;
		}
		
		if (null == env){
			return null;
		}
		if (null == name){
			return null;
		}
		
		String prefix = getPrefix();
		
		Module curModule = env.getCurModule();
		
		Module refModule = curModule.getModule(prefix);
		return new QName(module.getModulePrefix(refModule),name);
		
	}
	

	public QName getQName(){
		if (null == env){
			return null;
		}
		if (null == name){
			return null;
		}
		String prefix = getPrefix();
		
		return new QName(prefix,name);
	}
	public int compare(Object o) {
		return this.getName().compareTo(((ModelElement)o).getName());
	}
	
	
	
	public boolean isUpdated() {
		return isUpdated;
	}
	public void setUpdated(boolean isUpdated) {
		this.isUpdated = isUpdated;
	}
	public String getPrefix(){
		if (null != prefix){
			return prefix;
		}
		Module curModule = env.getCurModule();
		if(null == curModule){
			return null;
		}
		String prefix = null;
		if (curModule instanceof MainModule){
			prefix = ((MainModule)(curModule)).getPrefix();
		}
		else {
			SubModule sm= (SubModule)curModule;
			BelongsTo belongsTo = sm.getBelongsto();
			if (null == belongsTo){
				return null;
			}
			
			MainModule mm = (MainModule)(env.getModule(belongsTo.getName()));
			if (mm == null){
				return null;
			}
			
			prefix = mm.getPrefix();
		}
		
		return prefix;
	}
	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}
	/**
	 * ��ģ��Ԫ�����ΪYANG����ʽ
	 * @return
	 */
	public abstract YangStatement toYang();
	/**
	 * ��ģ��Ԫ�����ΪYIN����ʽ
	 * @return
	 */
	public abstract Element toYin();
	/**
	 * ��ģ��Ԫ�����ΪXML��ʽ
	 * @return
	 */
	public abstract Element toXML();
	/**
	 * ��һ��ģ��Ԫ��ת����YANG�����ı�
	 * @return
	 */
	public String toYANGString(YangFormatter formatter){
		
		YangStatement statement = writeYang();
		String yangStr;
	
		yangStr = YangWriter.toYangString(statement, formatter, null);

		
		return yangStr;
	}
	/**
	 * ��ģ��Ԫ�����ΪXML�ı���ʽ
	 * @return
	 */
	public String toXMLString(){
		String XMLString;
		Element element = writeXML();
		if (null == element){
			return null;
		}
		XMLOutputter xmloutput = new XMLOutputter();
		Document doc = new Document();
		doc.setRootElement(element);
		
		xmloutput.setFormat(Format.getPrettyFormat());
		XMLString = xmloutput.outputString(doc);
		return XMLString;
	}
	/**
	 * ��ģ��Ԫ�����ΪYIN�ı���ʽ
	 * @return
	 */
	public String toYINString(){
		String XMLString;
		Element element = writeYin();
		if (null == element){
			return null;
		}
		XMLOutputter xmloutput = new XMLOutputter();
		Document doc = new Document();
		doc.setRootElement(element);
		
		xmloutput.setFormat(Format.getPrettyFormat());
		XMLString = xmloutput.outputString(doc);
		return XMLString;
	}
	/**
	 * ��XMLԪ���ж�ȡģ��Ԫ��
	 * @param element
	 * @return
	 * @throws ModelException
	 */
	public abstract int readXML(Element element) throws ModelException;
	/**
	 * ��YINԪ���ж�ȡģ��Ԫ��
	 * @param element
	 * @return
	 * @throws ModelException
	 */
	public abstract int readYin(Element element) throws ModelException;
	/**
	 * ��YANG����ж�ȡģ��Ԫ��
	 * @param statement
	 * @return
	 * @throws YangParserException
	 */
	public abstract int readYANG(YangStatement statement) throws YangParserException,ModelException;
	
	/**
	 * 更新模型元素
	 */
	public abstract void update();
	/**
	 * ��XML������ģ��Ԫ��
	 * @param env
	 * @param element
	 * @return
	 * @throws ModelException
	 */
	public static ModelElement parseXML(Env env,Element element) throws ModelException {
		if (null == element){
			return null;
		}
		//�����ײ�����������
		ModelElement m = null;
		try {
			m = getInstance(env,element);
		} catch (InstantiationException e) {
			throw new ModelException(ErrTag.ERROR,
					e.toString());
			
		} catch (IllegalAccessException e) {
			throw new ModelException(ErrTag.ERROR,
					e.toString());
		} catch (ModelException e) {
			if (ErrTag.ERROR != e.getErrorTag()){
				System.out.println(e.toString());
				m.setErrorMsg(e.toString());
			}
			else {
				throw e; 
			}
		}
		if (null == m){
			return null;
		}
		Element root = null;
		if (element.getName().equals(XMLTag.XML_TAG_NODE)){
			root = element.getChildren().get(0);
		}
		else {
			root = element;
		}
		int result = MODELELEMENT_OK;
		List<Element> children = root.getChildren();
		int size = children.size();
		for (int i = 0;i < size;i++ ){
			Element child = children.get(i);
			if (null == child){
				continue;
			}
			Env subEnv = m.newSubEnv();
			//unknown
			if (ModelElement.isExtensionKeyword(env, child.getQualifiedName())){
				YangUnknown unknown = new YangUnknown(subEnv,child.getQualifiedName(),
						child.getTextTrim());
				unknown.readXML(child);
				m.addUnknown(unknown);
			}
			else if (XMLTag.isKeyword(child.getName())){
				result = m.readXML(child);
				if (MODELELEMENT_UNSUPPORT == result){
					ModelException e = new ModelException(ErrTag.WARNING,
							"un-supported statement:" + root.getName() + "[name=" 
					         + root.getChildText(XMLTag.XML_TAG_NAME) + "]"
							+ "/"+child.getName());
					System.out.println(e.toString());
				}
				else if (MODELELEMENT_OK != result){
					
						throw new ModelException(ErrTag.ERROR,
								"invalid statement:" + getElementAbsolutePath(child));
					
					
				}
			}

			else if (child.getName().equals(XMLTag.XML_TAG_NAME)
					|| child.getName().equals(XMLTag.XML_TAG_REGSTR)
					|| child.getName().equals(XMLTag.XML_TAG_MIN)
					|| child.getName().equals(XMLTag.XML_TAG_MAX)
					|| child.getName().equals(XMLTag.XML_TAG_VALUE)
					|| child.getName().equals(XMLTag.XML_TAG_BASETYPE)
					|| child.getName().equals(XMLTag.XML_TAG_DERIVEDTYPE)				
					){
				
			}
			else {
				throw new ModelException(ErrTag.ERROR,
						"invalid statement:" + root.getName() + "[name=" 
						         + root.getChildText(XMLTag.XML_TAG_NAME) + "]"
									+ "/"+child.getName());
			}	
		}

		return m;
	}	
	/**
	 * ��YIN������ģ��Ԫ��
	 * @param env
	 * @param element
	 * @return
	 * @throws ModelException
	 */
	public static ModelElement parseYin(Env env,Element element) throws ModelException {
		if (null == element){
			return null;
		}
		//�����ײ�����������
		ModelElement m = null;
		try {
			m = getYinInstance(env,element);
		} catch (InstantiationException e) {
			throw new ModelException(ErrTag.ERROR,
					e.toString());
			
		} catch (IllegalAccessException e) {
			throw new ModelException(ErrTag.ERROR,
					e.toString());
		} catch (ModelException e) {
			if (ErrTag.ERROR != e.getErrorTag()){
				System.out.println(e.toString());
				m.setErrorMsg(e.toString());
			}
			else {
				throw e; 
			}
		}
		if (null == m){
			return null;
		}
		Element root = element;
		
		int result = MODELELEMENT_OK;
		List<Element> children = root.getChildren();
		int size = children.size();
		for (int i = 0;i < size;i++ ){
			Element child = children.get(i);
			if (null == child){
				continue;
			}
			Env subEnv = m.newSubEnv();
			//unknown
			if (ModelElement.isExtensionKeyword(env, child.getQualifiedName())){
				YangUnknown unknown = new YangUnknown(subEnv,child.getQualifiedName());
				unknown.readYin(child);
				m.addUnknown(unknown);
			}
			else if (YangStatement.isYangKeyword(child.getName())){
				result = m.readYin(child);
				if (MODELELEMENT_UNSUPPORT == result){
					ModelException e = new ModelException(ErrTag.WARNING,
							"un-supported statement:" + root.getName() + "[name=" 
					         + root.getChildText(XMLTag.XML_TAG_NAME) + "]"
							+ "/"+child.getName());
					System.out.println(e.toString());
				}
				else if (MODELELEMENT_OK != result){
					
						throw new ModelException(ErrTag.ERROR,
								"invalid statement:" + getElementAbsolutePath(child));
					
					
				}
			}

		
			else {
				throw new ModelException(ErrTag.ERROR,
						"invalid statement:" + root.getName() + "[name=" 
						         + root.getChildText(XMLTag.XML_TAG_NAME) + "]"
									+ "/"+child.getName());
			}	
		}

		return m;
	}	
	/**
	 * ��YANG��������ģ��Ԫ��
	 * @param env
	 * @param statement
	 * @return
	 * @throws YangParserException
	 * @throws ModelException 
	 */
	public static ModelElement parseYANG(Env env,YangStatement statement) throws YangParserException, ModelException {
		if (null == statement){
			return null;
		}
		//�����ײ�����������
		ModelElement m = null;
		try {
			m = getInstance(env,statement.getKeyword(),statement.getArgument());
		} catch (InstantiationException e) {
			throw new YangParserException(statement.getParserEnv(),ErrTag.ERROR,
					statement.getParserEnv().getBeginLine(),
					statement.getParserEnv().getBeginColumn(),
					e.toString());
			
		} catch (IllegalAccessException e) {
			throw new YangParserException(statement.getParserEnv(),ErrTag.ERROR,
					statement.getParserEnv().getBeginLine(),
					statement.getParserEnv().getBeginColumn(),
					e.toString());
		} catch (ModelException e) {

			YangParserException ee =  new YangParserException(statement.getParserEnv(),e.getErrorTag(),
					statement.getParserEnv().getBeginLine(),
					statement.getParserEnv().getBeginColumn(),
					e.getDescription());
			if (ErrTag.ERROR != ee.getErrorTag()){
				System.out.println(ee.toString());				
			}
			else {
				throw ee; 
			}
		}
		if (null == m){
			return null;
		}
		
		int result = MODELELEMENT_OK;
		int size = statement.getChildrenNumber();
		for (int i = 0;i < size;i++ ){
			YangStatement subStatement = statement.getChild(i);
			if (null == subStatement){
				continue;
			}
			Env subEnv = m.newSubEnv();
			//unknown
			if (ModelElement.isExtensionKeyword(env, subStatement.getKeyword())){
				QName keyword = new QName(subStatement.getKeyword());
				String localName = keyword.getLocalName();
				if (null == localName){
					return null;
				}
				
				{
					YangUnknown unknown = new YangUnknown(subEnv,subStatement.getKeyword(),
							subStatement.getArgument());
					unknown.readYANG(subStatement);
					if (null != unknown){
						m.addUnknown(unknown);
					}
				}
				

			}
			else if (YangStatement.isYangKeyword(subStatement.getKeyword())){
				result = m.readYANG(subStatement);
				if (MODELELEMENT_UNSUPPORT == result){
					YangParserException e = new YangParserException(subStatement.getParserEnv(),ErrTag.WARNING,
							subStatement.getParserEnv().getBeginLine(),
							subStatement.getParserEnv().getBeginColumn(),
							"un-supported statement:" + subStatement.toString());
					System.out.println(e.toString());
				}
				else if (MODELELEMENT_OK != result){
					throw new YangParserException(subStatement.getParserEnv(),ErrTag.ERROR,
							subStatement.getParserEnv().getBeginLine(),
							subStatement.getParserEnv().getBeginColumn(),
							"invalid statement:" + subStatement.toString());
				}
			}
			else {
				throw new YangParserException(subStatement.getParserEnv(),ErrTag.ERROR,
						subStatement.getParserEnv().getBeginLine(),
						subStatement.getParserEnv().getBeginColumn(),
						"invalid statement:" + subStatement.toString());
			}	
		}

		return m;
	}
	/**
	 * ��ģ��Ԫ�����ΪYANG����ʽ����unknown
	 * @return
	 */
	public YangStatement writeYang(){
		YangStatement statement = toYang();
		if (null == statement){
			return null;
		}
		//unknown
		if (null != this.unknowns){
			int size = this.getUnknownsNumber();
			
			for (int i = 0; i < size; i++){
				YangUnknown un = this.getUnknown(i);
				if (null != un){
					YangStatement unstat = un.toYang();
					if (null != unstat){
						statement.addChild(unstat);
					}
				}
			}
		}
		return statement;
	}
	
	public Element writeYin(){
		Element element = toYin();
		if (null == element){
			return null;
		}
		Element root = element;
		
		if (null != this.unknowns){
			int size = this.getUnknownsNumber();
			
			for (int i = 0; i < size; i++){
				YangUnknown un = this.getUnknown(i);
				if (null != un){
					Element unstat = un.toYin();
					if (null != unstat){
						root.addContent(unstat);
					}
				}
			}
		}
		return element;
	}
	public Element writeXML(){

		Element element = toXML();
		if (null == element){
			return null;
		}
//		Element root = null;
//		if (null != this.getEnv().getTemp()){
//			root = (Element)(this.getEnv().getTemp());
//		}
//		else {
//			root = element;
//		}
		//unknown
//		if (null != this.unkonwns){
//			int size = this.getUnknownsNumber();
//			
//			for (int i = 0; i < size; i++){
//				YangUnknown un = this.getUnknown(i);
//				if (null != un){
//					Element unstat = un.toXML();
//					if (null != unstat){
//						root.addContent(unstat);
//					}
//				}
//			}
//		}
		return element;
	}
	/**
	 * ��ȡunknown�ĸ���
	 * @return
	 */
	public int getUnknownsNumber(){
		if (null == this.unknowns){
			return 0;
		}
		return this.unknowns.size();
	}
	/**
	 * ���unknown
	 * @param n
	 * @return
	 */
	public boolean addUnknown(YangUnknown n){
		if(null == n){
			return false;
		}
		
		if (null == this.unknowns){
			this.unknowns = new ArrayList<YangUnknown>(1);
		}
		if (null != getUnknown(n.getKeyword(),n.getName())){
			return false;
		}
		return this.unknowns.add(n);
	}
	/**
	 * �����Ż�ȡunknown
	 * @param index
	 * @return
	 */
	public YangUnknown getUnknown(int index){
		if (null == this.unknowns){
			return null;
		}
		if (index >= this.unknowns.size()){
			return null;
		}
		return this.unknowns.get(index);
	}
	/**
	 * ��ݹؼ��ֺ���ƻ�ȡunknown
	 * @param keyword
	 * @param name
	 * @return
	 */
	public YangUnknown getUnknown(String keyword,String name){
		if (null == this.unknowns){
			return null;
		}
		if (null == keyword){
			return null;
		}
		int size = unknowns.size();
		if (size <= 0){
			return null;
		}
		
		for (int i = 0; i < size; i++){
			YangUnknown n = this.unknowns.get(i);
			if (null != n){
				if (n.getKeyword().equals(keyword)){
					if (null == name && null == n.getName()){
						return n;
					}
					else if (null != name && null != n.getName()){
						if (name.equals(n.getName())){
							return n;
						}
					}

				}
			}
		}
		return null;
	}
	/**
	 * ��֤һ��ģ��Ԫ�ص���ȷ��
	 * @return
	 */
	public  Validator validate(){
//		if (!checkName(name)){
//			return false;
//		}
		Validator validator = new Validator();
		//unknown
		if (null != unknowns){
			int size = getUnknownsNumber();
			for (int i = 0; i < size; i++){
				YangUnknown un = getUnknown(i);
				if (null == un){
					continue;
				}
				Validator unkownValidator = un.validate();				
				validator.copy(unkownValidator);				
			}
		}
		
		return validator;
	}
	//public abstract static ModelElement create(Env env,String keyword,String name);

	public abstract boolean isFieldMandatory(String field);
	
	//public abstract MapInfo getMapInfo() throws SecurityException, NoSuchMethodException;

	

	/**
	 * �ж�ָ��������û��ָ������ֶ�
	 * @param field
	 * @return
	 */
	public boolean hasField(String field){
		Field fieldClass= null;
		try {
			fieldClass = this.getClass().getField(field);
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	
		if (null != fieldClass){
			return true;
		}
		
		return false;
	}
	/**
	 * �ж��ַ��Ƿ�Ϊ�մ�������ַ�Ϊnull�򳤶�Ϊ0������Ϊ�ǿմ�
	 * @param str
	 * @return
	 */
	public boolean isNullString(String str){
		if (null == str){
			return true;
		}
		
		if(0 == str.length()){
			return true;
		}
		
		return false;
	}
	
	/**
	 * ��ȡģ��Ԫ�ص�ӳ����Ϣ������ģ��Ԫ�ص��ֶΡ��ֶεĲ���������
	 * @return
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 */
	public abstract MapInfo getMapInfo() throws SecurityException, NoSuchMethodException;
	
	/**
	 * ��ȡģ��Ԫ�����
	 * @return
	 */
	public String getName() {
		return name;
	}
	/**
	 * ����ģ��Ԫ�����
	 * @param name
	 * @return
	 */
	public boolean setName(String name){
		if (checkName(name)){
			this.name = name;
			return true;
		}
		
		return false;
	}
	/**
	 * ���ģ��Ԫ�����
	 * @param name
	 * @return
	 */
	public boolean checkName(String name){
		return isIdentifier(name);
		
	}
	/**
	 * ��������list���Ƿ������ͬ����ƣ���������ͬ����ƣ�
	 * ����Ϊ�ǳ�ͻ��
	 * @return
	 */
	public static ModelElement[] checkNameConflict(ArrayList fields){
		if (null == fields){
			return null;
		}
		ModelElement[] resNodes = new DataDefElement[2];
		int size = fields.size();
		for (int i= 0; i < size;i++){
			ModelElement field= (ModelElement) fields.get(i);
			if (null == field){
				continue;
			}
			
			for (int j = i+1; j < size; j++){
				ModelElement otherField = (ModelElement) fields.get(j);
				if (null == otherField){
					continue;
				}
				
				if (field.getName().equals(otherField.getName())){
					resNodes[0] = otherField;
					resNodes[1] = field;
					return resNodes;
				}
				
			}
		}
		return null;
	}
	/**
	 * ��������link���Ƿ������ͬ����ƣ���������ͬ����ƣ�
	 * ����Ϊ�ǳ�ͻ��
	 * @return
	 */
	public static  ModelElement[]  checkNameConflict(Link fields){
		if (null == fields){
			return null;
		}
		ModelElement[] resNodes = new DataDefElement[2];
		int size = fields.size();
		for (int i= 0; i < size;i++){
			ModelElement field= (ModelElement) fields.get(i);
			if (null == field){
				continue;
			}
			
			for (int j = i+1; j < size; j++){
				ModelElement otherField = (ModelElement) fields.get(j);
				if (null == otherField){
					continue;
				}
				
				if (field.getName().equals(otherField.getName())){
					resNodes[0] = otherField;
					resNodes[1] = field;
					return resNodes;
				}
				
			}
		}
		return null;
	}	
	/**
	 * @return the env
	 */
	public Env getEnv() {
		return env;
	}
	/**
	 * @param env the env to set
	 */
	public void setEnv(Env env) {
		this.env = env;
	}

	/**
	 * Ϊģ��Ԫ�ص���Ԫ�ش�����������
	 * @return
	 */
	protected Env newSubEnv() {
		Env env = this.getEnv();
		Env subEnv = null;
		if (null == env){
			subEnv = new Env();
		}
		else {
			subEnv = env.clone();
		}
		
		subEnv.setParent(this);
		return subEnv;
	}
	/**
	 * @return the errorMsg
	 */
	public String getErrorMsg() {
		return errorMsg;
	}


	/**
	 * @param errorMsg the errorMsg to set
	 */
	public void setErrorMsg(String errorMsg) {
		if (null == this.errorMsg){
			this.errorMsg = errorMsg;
		}
		else {
			this.errorMsg.concat(errorMsg);
		}
		
	}
	
	public void setErrorMsg(ErrTag errorTag, String field, String descr){

	
	}
	public static boolean isAlpha(char c){
		if ((c >= 'A' && c <='Z')
				|| (c >= 'a' && c <= 'z')){
			return true;
		}
		return false;
	}
	public static boolean isDigit(char c){
		if (c >='0' && c <='9'){
			return true;
		}
		return false;
	}
	
	public static boolean isNodeIdentifier(Env env,String ref){
		if (null == ref){
			return false;
		}
		
		if (!ref.contains(":")){
			return isIdentifier(ref);
		}
		if (null == env){
			return false;
		}
		
		String[] strs = ref.split(":");
		if (2 != strs.length){
			return false;
		}
		String prefix = strs[0];
		String identifier = strs[1];
		if (!env.hasPrefix(prefix)){
			return false;
		}
		
		if (!isIdentifier(identifier)){
			return false;
		}
		
		return true;
	}
	/**
	 * �Ƿ��ǺϷ���ʵ�����
	 * @param id
	 * @return
	 */
	public static boolean isIdentifier(String id){
		if (null == id ){
			return false;
		}
		
		String str = id;
		str = str.toLowerCase();
		if (str.startsWith("xml")){
			return false;
		}
		
		int size = id.length();
		if (0 == size){
			return false;
		}
		for (int i = 0; i < size; i++){
			char c = id.charAt(i);
			//��������ĸ���»��߿�ͷ
			if (0 == i){
				if(!isAlpha(c)
						&& (c != '_')){
					return false;
				}
			}
			else {
				if (!isAlpha(c)
						&& !isDigit(c)
						&& (c != '_')
						&& (c != '-')
						&& (c != '.')){
					return false;
				}
			}
		}
		
		return true;
	}
	
	public static boolean isDescendantPath(Env env,String path){
		if (null == path){
			return false;
		}
		if (path.startsWith("/")){
			return false;
		}
		boolean containAbsolutePath = false;
		String absoultePath = null;
		String startNode= null;
		if (path.contains("/")){
			containAbsolutePath = true;
			int index = path.indexOf("/");
			startNode = path.substring(0, index);
			absoultePath = path.substring(index);
		}
		else {
			startNode = path;
		}
		
		if (!isNodeIdentifier(env,startNode)){
			return false;
		}
		
		if (containAbsolutePath){
			return isAbsolutePath(env,absoultePath);
		}
		return true;
		
		
	}
	
	public static boolean isAbsolutePath(Env env,String path){
		if (null == path){
			return false;
		}
		if (!path.startsWith("/")){
			return false;
		}
		if (path.length()<=1){
			return false;
		}
		String nodeIdentifiers[] = path.substring(1).split("/");
		if (null == nodeIdentifiers){
			return isNodeIdentifier(env,path.substring(1));
		}
		int size = nodeIdentifiers.length;
		for(int i = 0; i < size; i++){
			String nodeName = nodeIdentifiers[i];
			if (null == nodeName){
				return false;
			}
			
			if (!isNodeIdentifier(env,nodeName)){
				return false;
			}
		}
		
		return true;
		
	}
	
	public static String[] parseAbsolutePath(Env env,String path){
		if (!isAbsolutePath(env, path)){
			return null;
		}
		
		String nodeIdentifiers[] = path.substring(1).split("/");
		if (null == nodeIdentifiers){
			String nodes[] = new String[1];
			nodes[0]= path.substring(1);
			return nodes;
		}
		return nodeIdentifiers;
	}
	public static String[] parseDescendantPath(Env env,String path){
		if (!isDescendantPath(env, path)){
			return null;
		}
		
		String nodeIdentifiers[] = path.split("/");
		if (null == nodeIdentifiers){
			String nodes[] = new String[1];
			nodes[0]= path;
			return nodes;
		}
		return nodeIdentifiers;
	}
	
	public static Node getNodeByAbsPath(Env env,String absPath){
		
		String[] nodes = parseAbsolutePath(env,absPath);
		if (null == nodes){
			return null;
		}
		int size = nodes.length;
		Node node = null;
		for (int i = 0; i < size; i++){
			String nodeName = nodes[i];
			
			if (0 == i){
				Module curModule = env.getCurModule();
				String localPrefix = null;
				if (curModule instanceof MainModule){
					localPrefix = ((MainModule)(curModule)).getPrefix();
				}
				else {
					BelongsTo b = ((SubModule)(curModule)).getBelongsto();
					MainModule mm = (MainModule)env.getModule(b.getName());
					
					if (null == mm){
						return null;
					}
					localPrefix = mm.getPrefix();
				}
				
				QName qname = new QName(nodeName);
				
				if ((null == qname.getPrefix())
						|| (qname.getPrefix().equals(localPrefix))){
					node = curModule.getDataDefs().getSchemaNode(qname.getLocalName());
				}
				else {
					MainModule refModule = (MainModule) curModule.getModule(qname.getPrefix());
					
					node = refModule.getDataDefs().getSchemaNode(qname.getLocalName());
				}
			}
			else {
				
				QName qname = new QName(nodeName);
				
				node = node.getSchemaSon(qname.getLocalName());
			}
			if (null == node){
				return null;
			}
		}
		
		return  node;
		
	}
	
	public static Node getNodeByDescendantPath(Env env,ModelElement father,String path){
		
		String[] nodes = parseDescendantPath(env,path);
		if (null == nodes){
			return null;
		}
		int size = nodes.length;
		Node node = null;
		for (int i = 0; i < size; i++){
			String nodeName = nodes[i];
			
			if (0 == i){
//				Env fatherEnv = father.getEnv();
//				
//				Module curModule = fatherEnv.getCurModule();
//				String fatherPrefix = null;
//				if (curModule instanceof MainModule){
//					fatherPrefix = ((MainModule)(curModule)).getPrefix();
//				}
//				else {
//					MainModule mm = (((SubModule)(curModule)).getBelongsto()).getBelongs();
//					if (null == mm){
//						return null;
//					}
//					fatherPrefix = mm.getPrefix();
//				}
				QName qname = new QName(nodeName);
				if (father instanceof Node){										
					node = ((Node) father).getSchemaSon(qname.getLocalName());	
				}
				else if (father instanceof Uses){
					node = ((Uses) father).getSchemaNode(qname.getLocalName());
				}
				
			}
			else {
				
				QName qname = new QName(nodeName);
				
				node = node.getSchemaSon(qname.getLocalName());
			}
			if (null == node){
				return null;
			}
		}
		
		return  node;
		
	}
	/**
	 * ��ݱ������ȡ��չ�ؼ���ȫ��
	 * @param env
	 * @param localName
	 * @return
	 */
	public static String getExtensionKeyword(Env env,String localName){
		if (null == localName){
			return null;
		}
		
		//���ڱ�ģ�������չ�ؼ���
		Module m = env.getCurModule();
		if (null == m){
			return null;
		}
		
		//�Ȳ�һ�±�ģ���extension�б�����û��
		Extension extension = m.getExtension(localName);
		if (null != extension){
			if (m instanceof MainModule){
				return ((MainModule)m).getPrefix() + ":" +localName;
			}
			else {
				String prefix = ((SubModule)m).getBelongsto().getPrefix();
				return prefix + ":" + localName;
			}
		}
		
		//�ٲ鿴���ģ�����Ƿ��ж���
		int includenum = m.getIncludesNumber();
		for (int i = 0; i < includenum; i++){
			Include in = m.getInclude(i);
			if (null == in ){
				continue;
			}
			
			SubModule sm = in.getInclude();
			if (null != sm){
				if (null != sm.getExtension(localName)){
					if (m instanceof MainModule){
						return ((MainModule)m).getPrefix() + ":" +localName;
					}
					else {
						String prefix = ((SubModule)m).getBelongsto().getPrefix();
						return prefix + ":" + localName;
					}
				}
			}
		}
		//�ٲ鿴�����ģ�����Ƿ��ж���
		int importNum = m.getImportsNumber();
		for (int i = 0; i < importNum;i++){
			Import imp = m.getImport(i);
			if (null == imp){
				continue;
			}
			
			MainModule mm = imp.getImportedModule();
			if (null != mm){
				if (null != mm.getExtension(localName)){
					return imp.getPrefix() + ":" + localName;
				}
			}
			
		}
		
		return null;
	}
	/**
	 * �Ƿ�����չ�ؼ���
	 * @param env
	 * @param keyword
	 * @return
	 */
	public static boolean isExtensionKeyword(Env env,String keyword){
		if (null == keyword){
			return false;
		}
		if (!keyword.contains(":")){
			return false;
		}
		if (null == env){
			return false;
		}
		String[] strs = keyword.split(":");
		if (2 != strs.length){
			return false;
		}
		String prefix = strs[0];
		String identifier = strs[1];
		if (!env.hasPrefix(prefix)){
			return false;
		}
		
		if (!isIdentifier(identifier)){
			return false;
		}
		
		return true;
	}
	/**
	 * ���YANG�ؼ�����ɾ�������ʵ��
	 * @param env
	 * @param keyword
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws ModelException 
	 */
	public static ModelElement getInstance(Env env,String keyword,String name) throws InstantiationException, IllegalAccessException, ModelException{
		if (null == keyword){
			return null;
		}

		ModelElement m = null;
		//�����YANG�Ĺؼ���
		if (YangStatement.isYangKeyword(keyword)){
			if (keyword.equals(YangStatement.YANG_STATEMENT_MODULE)){
				m = MainModule.create(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_SUBMODULE)){
				m = new SubModule(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_BELONGSTO)){
				m = BelongsTo.class.newInstance();
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_IMPORT)){
				m = Import.create(env, name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_INCLUDE)){
				m = Include.class.newInstance();
			}
			else if (keyword.equals(YangKeyword.ANYXML.getKeyword())){
				m = new Anyxml(env,name);
			}
			else if (keyword.equals(YangKeyword.AUGMENT.getKeyword())){
				m = new Augment(env,name);
			}
			else if (keyword.equals(YangKeyword.USES.getKeyword())){
				m = new Uses(env,name);
			}
			else if (keyword.equals(YangKeyword.GROUPING.getKeyword())){
				m = new Grouping(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_TYPEDEF)){
				m = Typedef.class.newInstance();
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_TYPE)){
				m = Type.create(env, name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_BIT)){
				m = new Bit(name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_ENUM)){
				m = new Enum(name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_RANGE)){
				m = ((YangInteger)(env.getParent())).createRange();
				Range n = (Range)m;
				n.parseRangeExpression(name);
			}
			else if ( keyword.equals(YangStatement.YANG_STATEMENT_LENGTH)){
				if (env.getParent() instanceof YangString){
					m = ((YangString)(env.getParent())).createLength();
				}
				else if (env.getParent() instanceof Binary){
					m = ((Binary)(env.getParent())).createLength();
				}
				else {
					return null;
				}
				
				Range n = (Range)m;
				n.parseRangeExpression(name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_PATTERN)){
				m = Pattern.class.newInstance();
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_REVISION)){
				m = Revision.class.newInstance();
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_EXTENSION)){
				m = new Extension(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_FEATURE)){
				m = new Feature(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_IDENTITY)){
				m = new Identity(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_NOTIFICATION)){
				m = new Notification(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_RPC)){
				m = new Rpc(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_INPUT)){
				m = new Input(env);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_OUTPUT)){
				m = new Output(env);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_CONTAINER)
					|| keyword.equals(YangStatement.YANG_STATEMENT_CASE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_CHOICE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_LEAF)
					|| keyword.equals(YangStatement.YANG_STATEMENT_LEAFLIST)
					|| keyword.equals(YangStatement.YANG_STATEMENT_LIST)){
				m = Node.create(env, keyword, name);
			}
			//��Ԫ�أ�������������Ԫ�ص�Ԫ��
			else if (keyword.equals(YangStatement.YANG_STATEMENT_CONFIG)
					|| keyword.equals(YangStatement.YANG_STATEMENT_CONTACT)
					|| keyword.equals(YangStatement.YANG_STATEMENT_DEFAULT)
					|| keyword.equals(YangStatement.YANG_STATEMENT_DESCRIPTION)
					|| keyword.equals(YangStatement.YANG_STATEMENT_KEY)
					|| keyword.equals(YangStatement.YANG_STATEMENT_MANDATORY)
					|| keyword.equals(YangStatement.YANG_STATEMENT_MAXELEMENTS)
					|| keyword.equals(YangStatement.YANG_STATEMENT_MINELEMENTS)
					|| keyword.equals(YangStatement.YANG_STATEMENT_NAMESPACE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_ORGANIZATION)
					|| keyword.equals(YangStatement.YANG_STATEMENT_PATH)
					|| keyword.equals(YangStatement.YANG_STATEMENT_POSITION)
					|| keyword.equals(YangStatement.YANG_STATEMENT_PREFIX)
					|| keyword.equals(YangStatement.YANG_STATEMENT_PRESENCE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_REFERENCE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_REVISIONDATE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_STATUS)
					|| keyword.equals(YangStatement.YANG_STATEMENT_UNIQUE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_UNITS)
					|| keyword.equals(YangStatement.YANG_STATEMENT_VALUE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_ERRORAPPTAG)
					|| keyword.equals(YangStatement.YANG_STATEMENT_ERRORMESSAGE)
					){
				m = new SimpleElement(env,keyword,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_FEATURE)){
				m = new Feature(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_DEVIATION)){
				m = new Deviation(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_DEVIATE)){
				m = new Deviate(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_MUST)){
				m = new Must(env,name);
			}
			//��֧�ֵĹؼ���
			else {
				throw new ModelException(ErrTag.WARNING,
						"unsupported keyword:" + keyword);
			}
		}
		//��չ�ؼ���
		else if (isExtensionKeyword(env,keyword)){
			m = new YangUnknown(env,keyword);	
		}

		//�Ƿ��ؼ���
		else {
			throw new ModelException(ErrTag.ERROR,
					"invalid keyword:" + keyword);
		}
		if (null == m){
			return null;
		}
		if (null == m.env){
			m.setEnv(env);
		}
		if (null != name 
				&& (null == m.getName())){
			m.setName(name);
		}
		
		return m;
	}
	/**
	 * ���YINԪ����ɾ�������ʵ��
	 * @param env
	 * @param element
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws ModelException 
	 */
	public static ModelElement getYinInstance(Env env,Element element) throws InstantiationException, IllegalAccessException, ModelException{
		if (null == element){
			return null;
		}

		ModelElement m = null;
		//�����YANG�Ĺؼ���
		String keyword = element.getName();
		if (YangStatement.isYangKeyword(element.getName())){
			if (keyword.equals(YangStatement.YANG_STATEMENT_MODULE)){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = MainModule.create(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_SUBMODULE)){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = new SubModule(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_BELONGSTO)){
				String name = element.getAttributeValue(YangKeyword.MODULE.getKeyword());
				m = new BelongsTo();
				m.setName(name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_IMPORT)){
				String name = element.getAttributeValue(YangKeyword.MODULE.getKeyword());
				m = Import.create(env, name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_INCLUDE)){
				String name = element.getAttributeValue(YangKeyword.MODULE.getKeyword());
				m = new Include(env,name);
			}
			else if (keyword.equals(YangKeyword.ANYXML.getKeyword())){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = new Anyxml(env,name);
			}
			else if (keyword.equals(YangKeyword.AUGMENT.getKeyword())){
				String name = element.getAttributeValue("target-node");
				m = new Anyxml(env,name);
			}
			else if (keyword.equals(YangKeyword.USES.getKeyword())){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = new Uses(env,name);
			}
			else if (keyword.equals(YangKeyword.GROUPING.getKeyword())){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = new Grouping(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_TYPEDEF)){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = new Typedef(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_TYPE)){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = Type.create(env, name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_BIT)){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = new Bit(name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_ENUM)){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = new Enum(name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_RANGE)){
				m = ((YangInteger)(env.getParent())).createRange();
				Range n = (Range)m;
				
				String name = element.getAttributeValue(YangKeyword.VALUE.getKeyword());
				n.parseRangeExpression(name);
			}
			else if ( keyword.equals(YangStatement.YANG_STATEMENT_LENGTH)){
				if (env.getParent() instanceof YangString){
					m = ((YangString)(env.getParent())).createLength();
				}
				else if (env.getParent() instanceof Binary){
					m = ((Binary)(env.getParent())).createLength();
				}
				else {
					return null;
				}
				
				Range n = (Range)m;
				String name = element.getAttributeValue(YangKeyword.VALUE.getKeyword());
				n.parseRangeExpression(name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_PATTERN)){
				String name = element.getAttributeValue(YangKeyword.VALUE.getKeyword());
				m = new Pattern(name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_REVISION)){
				String name = element.getAttributeValue("date");
				m = new Revision(name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_EXTENSION)){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = new Extension(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_FEATURE)){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = new Feature(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_IDENTITY)){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = new Identity(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_NOTIFICATION)){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = new Notification(env,name);
			}
			
			else if (keyword.equals(YangStatement.YANG_STATEMENT_RPC)){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = new Rpc(env,name);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_INPUT)){
				m = new Input(env);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_OUTPUT)){
				m = new Output(env);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_CONTAINER)
					|| keyword.equals(YangStatement.YANG_STATEMENT_CASE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_CHOICE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_LEAF)
					|| keyword.equals(YangStatement.YANG_STATEMENT_LEAFLIST)
					|| keyword.equals(YangStatement.YANG_STATEMENT_LIST)){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = Node.create(env, keyword, name);
			}
			//��Ԫ�أ�������������Ԫ�ص�Ԫ��
			else if (keyword.equals(YangStatement.YANG_STATEMENT_CONFIG)
					|| keyword.equals(YangStatement.YANG_STATEMENT_CONTACT)
					|| keyword.equals(YangStatement.YANG_STATEMENT_DEFAULT)
					|| keyword.equals(YangStatement.YANG_STATEMENT_DESCRIPTION)
					|| keyword.equals(YangStatement.YANG_STATEMENT_KEY)
					|| keyword.equals(YangStatement.YANG_STATEMENT_MANDATORY)
					|| keyword.equals(YangStatement.YANG_STATEMENT_MAXELEMENTS)
					|| keyword.equals(YangStatement.YANG_STATEMENT_MINELEMENTS)
					|| keyword.equals(YangStatement.YANG_STATEMENT_NAMESPACE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_ORGANIZATION)
					|| keyword.equals(YangStatement.YANG_STATEMENT_PATH)
					|| keyword.equals(YangStatement.YANG_STATEMENT_POSITION)
					|| keyword.equals(YangStatement.YANG_STATEMENT_PREFIX)
					|| keyword.equals(YangStatement.YANG_STATEMENT_PRESENCE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_REFERENCE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_REVISIONDATE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_STATUS)
					|| keyword.equals(YangStatement.YANG_STATEMENT_UNIQUE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_UNITS)
					|| keyword.equals(YangStatement.YANG_STATEMENT_VALUE)
					|| keyword.equals(YangStatement.YANG_STATEMENT_ERRORAPPTAG)
					|| keyword.equals(YangStatement.YANG_STATEMENT_ERRORMESSAGE)					
					){
				
				m = new SimpleElement(env,keyword);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_FEATURE)){
				String name = element.getAttributeValue(XMLTag.XML_TAG_NAME);
				m = new Feature(env,name);
			}
			//��֧�ֵĹؼ���
			else {
				throw new ModelException(ErrTag.WARNING,
						"unsupported keyword:" + keyword);
			}
		}
		//��չ�ؼ���
		else if (isExtensionKeyword(env,keyword)){
			m = new YangUnknown(env,keyword);	
		}

		//�Ƿ��ؼ���
		else {
			throw new ModelException(ErrTag.ERROR,
					"invalid keyword:" + keyword);
		}
		if (null == m){
			return null;
		}
		if (null == m.env){
			m.setEnv(env);
		}
		
		
		return m;
	}
	/**
	 * ���XMLTAG��ɾ�������ʵ��
	 * @param env
	 * @param element
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws ModelException
	 */
	public static ModelElement getInstance(Env env,Element element) throws InstantiationException, IllegalAccessException, ModelException{
		if (null == element){
			return null;
		}

		ModelElement m = null;
		String keyword = element.getQualifiedName();
	
		
		//�����YANG�Ĺؼ���
		if (XMLTag.isKeyword(keyword)){
			if (keyword.equals(XMLTag.XML_TAG_MODULE)){
				
				String name = element.getChildText(XMLTag.XML_TAG_NAME);
				m = MainModule.create(env, name);
			}
			else if (keyword.equals(XMLTag.XML_TAG_SUBMODULE)){
				String name = element.getChildText(XMLTag.XML_TAG_NAME);
				m = new SubModule(env,name);
			}
			else if (keyword.equals(XMLTag.XML_TAG_BELONGSTO)){
				m = BelongsTo.class.newInstance();
			}
			else if (keyword.equals(XMLTag.XML_TAG_IMPORT)){
				m = Import.create(env, element);
			}
			else if (keyword.equals(XMLTag.XML_TAG_INCLUDE)){
				m = Include.class.newInstance();
			}
			else if (keyword.equals(XMLTag.XML_TAG_TYPEDEF)){
				m = Typedef.class.newInstance();
			}
			else if (keyword.equals(XMLTag.XML_TAG_TYPE)){
				m = Type.create(env, Type.getTypeName(element));
			}
			else if (keyword.equals(XMLTag.XML_TAG_BIT)){
				String bitName = element.getChildText(XMLTag.XML_TAG_NAME);
				m = new Bit(bitName);
			}
			else if (keyword.equals(XMLTag.XML_TAG_ENUM)){
				String enName = element.getChildText(XMLTag.XML_TAG_NAME);
				m = new Enum(enName);
			}
			else if (keyword.equals(YangStatement.YANG_STATEMENT_RANGE)){
				m = ((YangInteger)(env.getParent())).createRange();
				Range n = (Range)m;
				List<Element> childrenList = element.getChildren();
				int childrenSize = childrenList.size();
				for (int j = 0; j < childrenSize; j++){
					Element e = childrenList.get(j);
					if (e.getName().equals(XMLTag.XML_TAG_MIN)){
						Element max = childrenList.get(j+1);
						if (!max.getName().equals(XMLTag.XML_TAG_MAX)){
							return null;
						}
						RangeEx rEx = new RangeEx(n.getLowBound(),n.getHighBound(),e.getText(),max.getText());
						n.addRange(rEx);
						j++;
						continue;
					}
					else if (e.getName().equals(XMLTag.XML_TAG_VALUE)){
						Element value = childrenList.get(j);
						RangeEx re = new RangeEx(n.getLowBound(),n.getHighBound(), value.getText());
						n.addRange(re);
					}
					else {
						
					}
				}
				
			}
			else if ( keyword.equals(YangStatement.YANG_STATEMENT_LENGTH)){
				ModelElement me = env.getParent();
				if (me instanceof YangString){
					m = ((YangString)me).createLength();
				}
				else if (me instanceof Binary){
					m = ((Binary)me).createLength();
				}
				else {
					return null;
				}
				
				Range n = (Range)m;
				List<Element> childrenList = element.getChildren();
				int childrenSize = childrenList.size();
				for (int j = 0; j < childrenSize; j++){
					Element e = childrenList.get(j);
					if (e.getName().equals(XMLTag.XML_TAG_MIN)){
						Element max = childrenList.get(j+1);
						if (!max.getName().equals(XMLTag.XML_TAG_MAX)){
							return null;
						}
						RangeEx rEx = new RangeEx(n.getLowBound(),n.getHighBound(),e.getText(),max.getText());
						n.addRange(rEx);
						j++;
						continue;
					}
					else if (e.getName().equals(XMLTag.XML_TAG_VALUE)){
						Element value = childrenList.get(j);
						RangeEx re = new RangeEx(n.getLowBound(),n.getHighBound(), value.getText());
						n.addRange(re);
					}
					else {
						
					}
				}
			}
			else if (keyword.equals(XMLTag.XML_TAG_PATTERN)){
				m = new Pattern(element.getChildText(XMLTag.XML_TAG_REGSTR));
			}
			else if (keyword.equals(XMLTag.XML_TAG_REVISION)){
				m = Revision.class.newInstance();
			}
			else if (keyword.equals(XMLTag.XML_TAG_EXTENSION)){
				m = new Extension(env,element.getChildText(XMLTag.XML_TAG_NAME));
			}
			else if (keyword.equals(XMLTag.XML_TAG_FEATURE)){
				m = new Feature(env,element.getChildText(XMLTag.XML_TAG_NAME));
			}
			else if (keyword.equals(XMLTag.XML_TAG_DEVIATION)){
				m = new Deviation(env,element.getChildText(XMLTag.XML_TAG_NAME));
			}
			else if (keyword.equals(XMLTag.XML_TAG_DEVIATE)){
				m = new Deviate(env,element.getChildText(XMLTag.XML_TAG_NAME));
			}
			else if (keyword.equals(XMLTag.XML_TAG_NODE)){
				m = Node.create(env, element);
			}
			//��Ԫ�أ�������������Ԫ�ص�Ԫ��
			else if (keyword.equals(XMLTag.XML_TAG_CONFIG)
					|| keyword.equals(XMLTag.XML_TAG_CONTACT)
					|| keyword.equals(XMLTag.XML_TAG_DEFAULT)
					|| keyword.equals(XMLTag.XML_TAG_DESCRIPTION)
					|| keyword.equals(XMLTag.XML_TAG_KEYS)
					|| keyword.equals(XMLTag.XML_TAG_MANDATORY)
					|| keyword.equals(XMLTag.XML_TAG_MAXELEMENTS)
					|| keyword.equals(XMLTag.XML_TAG_MINELEMENTS)
					|| keyword.equals(XMLTag.XML_TAG_NAMESPACE)
					|| keyword.equals(XMLTag.XML_TAG_ORGANIZATION)
					|| keyword.equals(XMLTag.XML_TAG_PATH)
					|| keyword.equals(XMLTag.XML_TAG_POSITION)
					|| keyword.equals(XMLTag.XML_TAG_PREFIX)
					|| keyword.equals(XMLTag.XML_TAG_PRESENCE)
					|| keyword.equals(XMLTag.XML_TAG_REFERENCE)
					|| keyword.equals(XMLTag.XML_TAG_REVISIONDATE)
					|| keyword.equals(XMLTag.XML_TAG_STATUS)
					|| keyword.equals(XMLTag.XML_TAG_UNIQUES)
					|| keyword.equals(XMLTag.XML_TAG_UNITS)
					|| keyword.equals(XMLTag.XML_TAG_VALUE)
					){
				String name = null;
				if (keyword.equals(XMLTag.XML_TAG_KEYS)
						|| keyword.equals(XMLTag.XML_TAG_UNIQUES)){
					List<Element> uniques = element.getChildren();
					if (null == uniques){
						return null;
					}
					int uniquesize = uniques.size();
					for (int j = 0; j < uniquesize; j++){
						Element unique = uniques.get(j);
						if (null == unique){
							continue;
						}
						if (keyword.equals(XMLTag.XML_TAG_KEYS)){
							if (!unique.getName().equals(XMLTag.XML_TAG_KEY)){
								return null;
							}
						}
						else {
							if (!unique.getName().equals(XMLTag.XML_TAG_UNIQUE)){
								return null;
							}
						}
						
						if (null == name){
							name = unique.getText();
						}
						else {
							name.concat(" "+unique.getText());
						}
						
					}
					if (keyword.equals(XMLTag.XML_TAG_KEYS)){
						keyword = XMLTag.XML_TAG_KEY;
					}
					else {
						keyword = XMLTag.XML_TAG_UNIQUE;
					}
				}
				else
				{
					name = element.getText();
				}
				
				m = new SimpleElement(env,keyword,name);
			}
			//��֧�ֵĹؼ���
			else {
				throw new ModelException(ErrTag.WARNING,
						"unsupported keyword:" + keyword);
			}
		}
		//��չ�ؼ���
		else if (isExtensionKeyword(env,keyword)){
			m = new YangUnknown(env,keyword);	
		}
		//�Ƿ��ؼ���
		else {
			throw new ModelException(ErrTag.ERROR,
					"invalid keyword:" + keyword);
		}
		if (null == m){
			return null;
		}
		if (null == m.env){
			m.setEnv(env);
		}
		String name = element.getChildText(XMLTag.XML_TAG_NAME);
		if (null !=  name
				&& (null == m.getName())){
			m.setName(name);
		}
		
		return m;
	}
	public static Element adJustElement(Element element){
		if (null == element){
			return null;
		}
		if (element.getName().equals(XMLTag.XML_TAG_NODE)){
			Element subElement = null;
			
			subElement = element.getChild(XMLTag.XML_TAG_LEAF);
			if (null != subElement){
				return subElement;
			}
			
			subElement = element.getChild(XMLTag.XML_TAG_LEAFLIST);
			if (null != subElement){
				return subElement;
			}
			
			subElement = element.getChild(XMLTag.XML_TAG_LIST);
			if (null != subElement){
				return subElement;
			}
			
			subElement = element.getChild(XMLTag.XML_TAG_CONTAINER);
			if (null != subElement){
				return subElement;
			}
			
			subElement = element.getChild(XMLTag.XML_TAG_CASE);
			if (null != subElement){
				return subElement;
			}
			
			subElement = element.getChild(XMLTag.XML_TAG_CHOICE);
			if (null != subElement){
				return subElement;
			}
			
			return null;
		}
		else {
			return element;
		}
	}
	public static String getElementAbsolutePath(Element element){
		
		if (null == element){
			return null;
		}
		element = adJustElement(element);
		StringBuffer pathString= new StringBuffer();
		Stack<String> pathStack = new Stack<String>();
		while(!element.isRootElement()){
			if (null == element){
				break;
			}
			StringBuffer pathNode= new StringBuffer();
			pathNode.append(element.getName());
			if (element.getName().equals(XMLTag.XML_TAG_CASE)){
				pathNode.append("[name=" + element.getChildText(XMLTag.XML_TAG_VALUE) + "]");
			}
			else if (element.getName().equals(XMLTag.XML_TAG_TYPE)){
				String typename= null;
				
				if (null != (typename = element.getChildText(XMLTag.XML_TAG_BASETYPE))){
					
				}
				else if (null != (typename = element.getChildText(XMLTag.XML_TAG_DERIVEDTYPE))){
					
				}
				else{
					return null;
				}
				pathNode.append("[name=" + typename + "]");
				
			}
			else if (element.getName().equals(XMLTag.XML_TAG_NODE)){
				
			}
			else {
				pathNode.append("[name=" + element.getChildText(XMLTag.XML_TAG_NAME) + "]");
			}
			
			pathStack.push(pathNode.toString());
			element = element.getParentElement();
		}
		
		while(!pathStack.isEmpty()){
			pathString.append("/" + pathStack.pop());
		}
		return pathString.toString();
	}
	
	
}
